package rtcf.framework{
	import flash.events.AsyncErrorEvent;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.NetConnection;

	[Event(name="connectResult",   type="flash.events.NetStatusEvent")]
	[Event(name="connectFault",    type="flash.events.NetStatusEvent")]
	[Event(name="disconnectFault", type="flash.events.NetStatusEvent")]
	
	/** 
	 * Simple NetConnection subclass that makes managing connection events easier. 
	 * 
	 */
	public class RTCFConnection extends NetConnection{
		static public const NOT_CONNECTED:Number = 0;
		static public const CONNECTING:Number = 1;
		static public const CONNECTED:Number = 2;
				
		public var currentState:Number = NOT_CONNECTED;
		public var dispatchCloseEventAfterClose:Boolean = true;
		public var dispatchCloseEventAfterReject:Boolean = false;		

		public function RTCFConnection(){
			super();
			addEventListener(NetStatusEvent.NET_STATUS, handleConnectionStatusEvent);
			addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleSecurityError);
			addEventListener(AsyncErrorEvent.ASYNC_ERROR, handleAsyncError);
			addEventListener(IOErrorEvent.IO_ERROR, handleIOError);					
		}

		override public function connect (command:String, ... arguments):void{
			// Handle the command paramter separately to avoid an incompatible override compiler error.
			arguments.unshift(command);
			currentState = CONNECTING;
			super.connect.apply(this, arguments);
		}	
		
		override public function close():void{
			if (!dispatchCloseEventAfterClose) currentState = NOT_CONNECTED;
			super.close();
		}	

		protected function handleConnectionStatusEvent(event:NetStatusEvent):void{
			//trace("handleConnectionStatusEvent> code: " + event.info.code);
			var codeTokens:Array = event.info.code.split(".");
			// Ignore Call related events and only process Connect events:
			if (codeTokens[1] == "Connect"){
				switch (codeTokens[2]){
					case "Success":
						currentState = CONNECTED;
						dispatchEvent(new NetStatusEvent("connectResult", false, false, event.info));
						break;
					case "Closed":
						switch(currentState){
							case CONNECTING:
								dispatchEvent(new NetStatusEvent("connectFault", false, false, event.info));
								break;
							case CONNECTED:
								dispatchEvent(new NetStatusEvent("disconnectFault", false, false, event.info));
								break;									
							case NOT_CONNECTED:
								// do nothing 
								break;														
						}
						currentState = NOT_CONNECTED;
						break;
					case "Rejected":
						dispatchEvent(new NetStatusEvent("connectFault", false, false, event.info));
						if(!dispatchCloseEventAfterReject) currentState = NOT_CONNECTED;
						break;	
					default:
						if(currentState == CONNECTED){
							dispatchEvent(new NetStatusEvent("disconnectFault", false, false, event.info));
						}
						else {
							dispatchEvent(new NetStatusEvent("connectFault", false, false, event.info));
						}
						currentState = NOT_CONNECTED;
				}
			}
		}
		
		/* WARNING THESE THREE FUNCTIONS ARE NOT TESTED! They all send back a NetStatus event with an info object instead of the usual zoo of events and faults. */
		
		protected function handleSecurityError(event:SecurityErrorEvent):void{
			//trace("RTCFConnection.handleSecurityError> " + event.text);
			if(currentState == CONNECTED){
				dispatchEvent(new NetStatusEvent("disconnectFault", false, false, {text: event.text}));
			}
			else {
				dispatchEvent(new NetStatusEvent("connectFault", false, false, {text: event.text}));
			}
		}
		
		protected function handleAsyncError(event:AsyncErrorEvent):void{
			//trace("RTCFConnection.handleAsyncError> " + event.error.message);
			if(currentState == CONNECTED){
				dispatchEvent(new NetStatusEvent("disconnectFault", false, false, {text: event.text, name:event.error.name, errorID:event.error.errorID, message: event.error.message}));
			}
			else {
				dispatchEvent(new NetStatusEvent("connectFault", false, false, {text: event.text, name:event.error.name, errorID:event.error.errorID, message: event.error.message}));
			}
		}
		
		
		protected function handleIOError(event:IOErrorEvent):void{
			//trace("RTCFConnection.handleIOError> " + event.text);
			if(currentState == CONNECTED){
				dispatchEvent(new NetStatusEvent("disconnectFault", false, false, {text: event.text}));
			}
			else {
				dispatchEvent(new NetStatusEvent("connectFault", false, false, {text: event.text}));
			}
		}
		
	}
}